Haxe + CreateJS 開発メモ#3 jQuery Pluginを作る
FlashDevelop + Haxe + CreateJS の組み合わせで、ActionScript による Flash 開発のような感覚で canvas を使用したアプリケーション開発が行えることは、前回までで紹介した通りです。しかし FlashDevelop は、HTML や CSS を含めた WEB アプリケーション全体を構築するための機能は備えていません。HTML や CSS を記述することも一応は出来ますが効率は悪いです。
実際の開発では、複雑なロジックを含む機能を Haxe で作成し、それを別のIDEやフレームワークを使ったアプリケーションに組み込むといった作業が発生するはずです。
そこで今回は、Haxe で CreateJS を使用した jQuery Plugin を作成してみます。Haxe で作成した機能を jQuery Plugin 化することで、アプリケーションへの組み込み作業を簡単に出来ます。
jQuery Plugin については、以下の記事を読むとよく分かります。
HTML5 × CSS3 × jQueryを真面目に勉強 ? #8 jQueryプラグインの作り方について詳しく
プロジェクトの準備
プロジェクトを新規作成し、コンパイラー設定でjQueryExternを使用する設定を行います。
jQueryExternのインストールや、コンパイラー設定の細かいやり方に関しては、このシリーズの前々回の記事を参照してください。
jQuery.fn の拡張
jQuery Plugin の実装は、jQuery.fn を拡張して行います。jQueryExtern で jQuery オブジェクトにアクセスするには、JQueryStatic クラスを使用します。JQueryStatic クラスは、jQuery\JQuery.hx 内で定義されているインナークラスなので、いきなりタイプしても自動インポートが上手くいきません。ここに限っては、import 文は自力で記述した方が無難です。
import jQuery.JQuery;
また、JQueryStatic に fn プロパティは定義されていないので、とりあえず Dynamic 型に代入してから fn.extend メソッドを呼び出します。
var jq:Dynamic = JQueryStatic; jq.fn.extend( { //・・・処理・・・ });
拡張して追加したメソッド内では、this で DOM 要素を保持した JQuery オブジェクトが取得できますが、そのまま this と記述すると、Haxe コンパイラは this を Main クラスのインスタンスと解釈してしまい、コンパイルエラーになってしまいます。そこで、eval() メソッドを使用して、実行時の this をローカル変数に代入して、以降の処理で使用します。また、メソッドチェーンのために、最後に return しておきます。
var elements:JQuery = Lib.eval("this"); //・・・処理・・・ return elements;
以上の三点を踏まえた、jQuery Plugin のテンプレートです。
package ; import jQuery.JQuery; import js.Lib; class Main { static function main() { new Main(); } public function new() { var jq:Dynamic = JQueryStatic; jq.fn.extend( { yourPluginMethod: function(?options:Dynamic):JQuery { var elements:JQuery = Lib.eval("this"); //・・・処理・・・ return elements; } } ); } }
Dynamic や eval() を使用しているために少し無理矢理感がありますが、一応これで上手くいきます。
実装サンプル
以下、CreateJS を使ったプラグインのサンプルです。
Main.hx
package ; import createjs.easeljs.MouseEvent; import createjs.easeljs.Stage; import createjs.easeljs.Ticker; import jQuery.JQuery; import js.Lib; class Main { //エントリポイント static function main() { new Main(); } //ステージ private var stage:Stage; //オプション private var options:Dynamic; //コンストラクタ public function new() { //optionsのデフォルト値 var defaults = { radius: 5, alphaDecrement: 0.02, scaleMagnification: 1.1 } var jq:Dynamic = JQueryStatic; jq.fn.extend( { //rippleメソッドを追加 ripple: function(?options:Dynamic):JQuery { //デフォルトオプションを引数で上書き this.options = JQueryStatic.extend({}, defaults, options); var elements:JQuery = Lib.eval("this"); initStage(elements); return elements; } } ); } //ステージの初期処理 private function initStage(elements:JQuery):Void { for (i in 0...elements.length) { var element:Dynamic = elements[i]; stage = new Stage(cast element); stage.onMouseUp = stageOnMouseUp; Ticker.addListener(stage); Ticker.setFPS(60); break; } } //MouseUpイベントハンドラ private function stageOnMouseUp(e:MouseEvent):Void { //Circleをステージに追加 var circle:Circle = new Circle(options); circle.x = e.stageX; circle.y = e.stageY; stage.addChild(circle); } }
Circle.hx
package ; import createjs.easeljs.Container; import createjs.easeljs.Graphics; import createjs.easeljs.Shape;
class Circle extends Shape {
//コンストラクタ public function new(options:Dynamic) { super();
//ランダムな色で円を描く var g:Graphics = graphics; var color:Int = Math.round(16777215 * Math.random()); g.beginFill("#" + StringTools.hex(color)); g.drawCircle(0, 0, options.radius); g.endFill();
onTick = function() { alpha -= options.alphaDecrement; scaleX = scaleY *= options.scaleMagnification; if (alpha <= 0) { cast(parent, Container).removeChild(this); } } } } [/as3]
ripple.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <title>HaxeJQPluginSample</title> <meta name="description" content="" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script src="http://code.createjs.com/easeljs-0.5.0.min.js"></script> <script src="jquery.ripple.js"></script> <script type="text/javascript"> $(function() { $('#canvas').ripple({radius: 10}); }); </script> </head> <body> <p>キャンバスをクリック!</p> <canvas id="canvas" width="400" height="400" style="background-color:#EEE"></canvas> </body> </html>
実行結果
非常に簡潔な記述で、HTMLへ組み込む事ができました。通常のHTMLとCreateJSを使用する箇所で分業を行う場合など、このようなやり方で進めれば、スムーズに行くと思います。